/**
  ******************************************************************************
  * @file    shell-commands.c
  * @author  Iron
  * @date    2021-01-29
  * @version v1.0
  * @brief   shell-commands c file
  */

/** @addtogroup GROUP_SHELL
  * @{
  */

/* Private includes ----------------------------------------------------------*/
#include "shell.h"
#include "shell-history.h"
#include "shell-commands.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
//static struct shell_command_head_t shell_command_set_head = SLIST_HEAD_INITIALIZER();
static struct shell_command_set_t builtin_shell_command_set;

/* Private function prototypes -----------------------------------------------*/
void bsp_system_reset(void);

/*---------------------------------------------------------------------------*/
int shell_commands_init(struct shell_command_sets_t *sets)
{
    debug_assert(sets);

    /* Initialize the list. */
    SLIST_INIT(sets);

    /* Initialize the builtin shell commands list. */
    SLIST_INSERT_HEAD(sets, &builtin_shell_command_set, next);

    return 0;
}

/*---------------------------------------------------------------------------*/
int shell_command_set_register(struct shell_command_sets_t *sets, struct shell_command_set_t *set)
{
    struct shell_command_set_t *var = NULL;

    debug_assert(sets);

    if (SLIST_EMPTY(sets))
    {
        SLIST_INSERT_HEAD(sets, set, next);
    }
    else
    {
        SLIST_FOREACH(var, sets, next)
        {
            if (var->next.sle_next == NULL)
            {
                SLIST_INSERT_AFTER(var, set, next);
                break;
            }
        }
    }

    return 0;
}

/*---------------------------------------------------------------------------*/
int shell_command_set_deregister(struct shell_command_sets_t *sets, struct shell_command_set_t *set)
{
    debug_assert(sets);

    SLIST_REMOVE(sets, set, shell_command_set_t, next);

    return 0;
}

/*---------------------------------------------------------------------------*/
const struct shell_command_t *shell_command_lookup(struct shell_command_sets_t *sets, const char *name, int len)
{
    struct shell_command_set_t *set;
    const struct shell_command_t *cmd;

    debug_assert(sets);

    SLIST_FOREACH(set, sets, next)
    {
        for (cmd = set->commands; cmd->name != NULL; ++cmd)
        {
            if (!strncmp(cmd->name, name, len))
            {
                return cmd;
            }
        }
    }

    return NULL;
}

const char *shell_commands_match(struct shell_command_sets_t *sets, char *buf, int len)
{
    const struct shell_command_t *cmd;

    cmd = shell_command_lookup(sets, buf, len);

    return (cmd == NULL) ? NULL : cmd->name;
}

/*---------------------------------------------------------------------------*/
static char cmd_history(shell_context_t *shell, char *args)
{
    struct shell_history_head_t *phead;
    struct shell_history_t *elm;
    int index;

    debug_assert(shell);
    
    if(shell->history == NULL)
    {
        shell->shell_printf("Shell history not init.\r\n");
        return NULL;
    }

    shell->shell_printf("shell history queue:\r\n");
    
    phead = &shell->history->head;
    index = 0;

    TAILQ_FOREACH(elm, phead, entries)
    {
        index++;
        shell->shell_printf("%d: %s\r\n", index, elm->commands);
    }

    return NULL;
}

/*---------------------------------------------------------------------------*/
static char cmd_help(shell_context_t *shell, char *args)
{
    struct shell_command_sets_t *sets = shell->command_sets;
    struct shell_command_set_t *set;
    const struct shell_command_t *cmd;

    debug_assert(shell);
    debug_assert(shell->command_sets);

    shell->shell_printf("Available commands:\n");

    /* Note: we explicitly don't expend any code space to deal with shadowing */
    SLIST_FOREACH(set, sets, next)
    {
        for (cmd = set->commands; cmd->name != NULL; ++cmd)
        {
            shell->shell_printf("%s\n", cmd->help);
        }
    }

    return NULL;
}

/*---------------------------------------------------------------------------*/
static char cmd_clear(shell_context_t *shell, char *args)
{
    debug_assert(shell);

    shell->shell_printf("\033[2J"); // VT100 终端控制码，清屏
    shell->shell_printf("\033[%d;%dH", 0, 0); // VT100 终端控制码，光标移到 y,x

    return NULL;
}

/*---------------------------------------------------------------------------*/
static char cmd_reboot(shell_context_t *shell, char *args)
{
    debug_assert(shell);

    shell->shell_printf("rebooting\n");

    bsp_system_reset();

    return NULL;
}

/*---------------------------------------------------------------------------*/
const struct shell_command_t builtin_shell_commands[] =
{
    { "help",                 cmd_help,                 "'> help': Shows this help" },
    { "clear",                cmd_clear,                "'> clear': Clear the screen" },
    { "history",              cmd_history,               "'> history': List shell history input." },
    { "reboot",               cmd_reboot,               "'> reboot': Reboot the board by watchdog_reboot()" },
//    { "log",                  cmd_log,                  "'> log module level': Sets log level (0--4) for a given module (or \"all\"). For module \"mac\", level 4 also enables per-slot logging." },
    { NULL, NULL, NULL },
};

static struct shell_command_set_t builtin_shell_command_set =
{
    .next = NULL,
    .commands = builtin_shell_commands,
};

/**
  * @}
  */

/******************* (C)COPYRIGHT 2021 ***** END OF FILE *********************/
